<template>
  <div v-if="ready" class="photo-swiper" :class="{ swiping }" ref="photoSwiper">
    <div
      v-for="(item, i) in renderItems"
      class="photo-item"
      :class="{
        curr: currIndex === i,
        prev: prevIndex === i,
        next: nextIndex === i,
        'prev-out': prevIndex > i,
        'next-out': nextIndex < i,
      }"
      :key="item.url"
      :style="{
        transitionDuration: i >= prevIndex && i <= nextIndex ? transitionDuration : '',
        transform: swiping
          ? currIndex === i
            ? currTranslateX
            : prevIndex === i
            ? prevTranslateX
            : nextIndex === i
            ? nextTranslateX
            : ''
          : '',
      }"
      @transitionend.self="currIndex === i && resetTransitionDuration()"
    >
      <EncryptImage :src="item.url">
        <template #loading>
          <Loading></Loading>
        </template>
      </EncryptImage>
      <WaterMark v-if="watermark"></WaterMark>
      <div v-if="i === MAX_SHOW_COUNT - 1" class="view-more">
        <button class="font-size-12 font-weight-500 line-height-120 text-center" @click="$emit('fullscreen')">
          {{ $t('message.more') }}
        </button>
      </div>
    </div>
    <div v-if="items.length > 1" class="index-number font-size-14 font-weight-500 line-height-140">
      {{ currIndex + 1 + '/' + items.length }}
    </div>
    <div v-if="items.length > 1" class="index-circle gap-row-5">
      <div v-for="(_, i) in renderItems" class="circle" :class="{ active: currIndex === i }" :key="i"></div>
    </div>
    <div v-if="isDesktop && currIndex > 0" class="arrow-left pointer" @click.stop="prev">
      <Icon name="arrowRight" size="40"></Icon>
    </div>
    <div v-if="isDesktop && currIndex < renderItems.length - 1" class="arrow-right pointer" @click.stop="next">
      <Icon name="arrowRight" size="40"></Icon>
    </div>
  </div>
</template>

<script setup>
import { computed, ref, watch } from 'vue'
import { useThrottleFn } from '@vueuse/core'
import { storeToRefs } from 'pinia'
import { useAppStore } from '@/store/app'
import { useFullscreenPhotoStore } from '@/store/fullscreen-photo'
import { getDecryptDataBlob } from '@/utils/encrypt-img-store'
import WaterMark from '@/components/common/WaterMark.vue'
import EncryptImage from '@/components/multimedia/EncryptImage.vue'
import { useOnceOrDbClick } from '@/compositions/mobile/onceOrDbClick'
import { usePreventTouchmove } from '@/compositions/mobile/preventTouchmove'
import { useSwipe } from '@/compositions/mobile/swipe'
import { useStat } from '@/compositions/viewer/stat'
import { FULLSCREEN_PHOTO_TYPE, FULLSCREEN_TYPE_THRESHOLD, MEDIA_TYPE } from '@/constant'
import Loading from '../common/Loading.vue'

const MAX_SHOW_COUNT = 6
const HALF_VIEW_WIDTH = window.innerWidth / 2

const props = defineProps({
  active: { type: Boolean, required: true },
  ready: { type: Boolean, required: true },
  item: { type: Object, required: true },
  lock: { type: Boolean, default: false },
  fullscreen: { type: Boolean, default: false },
  statInfo: { type: Object, required: false },
  watermark: { type: Boolean, default: false },
})

const emits = defineEmits(['fullscreen', 'exit-fullscreen', 'dbclick'])

const appStore = useAppStore()
const { isDesktop } = storeToRefs(appStore)

/**
 * 這裡的 items 是由 img_path 和 img_more 組成的
 * img_path 是第一張圖片的路徑
 * img_more 是第二張圖片及之後的路徑
 * 如果是單圖就會直接顯示 img_path
 *（以上都是歷史包袱）
 *
 * 是否要模糊化圖片取決於 lock 的值
 */
const items = computed(() => {
  const item = props.item
  const imgPathKey = props.lock ? 'img_path_blur' : 'img_path'
  const imgMoreKey = props.lock ? 'img_more_blur' : 'img_more'
  const firstImg = {
    url: item[imgPathKey],
    width: item.img_width,
    height: item.img_height,
  }
  if (item[imgMoreKey]) {
    return [firstImg, ...item[imgMoreKey]]
  }
  return [firstImg]
})
const renderItems = computed(() => {
  const len = Math.min(MAX_SHOW_COUNT, items.value.length)
  return items.value.slice(0, len)
})

const photoSwiper = ref(null)
const currIndex = ref(0)
const prevIndex = computed(() => currIndex.value - 1)
const nextIndex = computed(() => currIndex.value + 1)

const prev = useThrottleFn(() => {
  if (currIndex.value > 0) {
    currIndex.value -= 1
  }
}, 300)
const next = useThrottleFn(() => {
  if (currIndex.value < renderItems.value.length - 1) {
    currIndex.value += 1
  }
}, 300)

// 滑動操作
const { offset, swiping, transitionDuration, resetTransitionDuration } = useSwipe(photoSwiper, {
  edgeDist: 20,
  isBlockBackward: () => currIndex.value === 0,
  isBlockForward: () => currIndex.value === renderItems.value.length - 1,
  onBackward: prev,
  onForward: next,
})

// 滑動中關閉瀏覽器預設行為
usePreventTouchmove(
  photoSwiper,
  () => offset.value !== 0 || currIndex.value === 0 || currIndex.value === renderItems.value.length - 1,
)

// 滑動時的樣式
const currTranslateX = computed(() => {
  if (swiping.value) {
    if (offset.value > 0) {
      const _offset = Math.min(offset.value, HALF_VIEW_WIDTH * 2)
      return `translateX(${-_offset}px)`
    }
    if (offset.value < 0) {
      const _offset = Math.min(-offset.value, HALF_VIEW_WIDTH * 2)
      return `translateX(${_offset}px)`
    }
  }
  return ''
})
const prevTranslateX = computed(() => {
  if (swiping.value && offset.value < 0) {
    const _offset = Math.min(offset.value, HALF_VIEW_WIDTH * 2)
    return `translateX(calc(-100% - ${_offset}px))`
  }
  return ''
})
const nextTranslateX = computed(() => {
  if (swiping.value && offset.value > 0) {
    const _offset = Math.min(offset.value, HALF_VIEW_WIDTH * 2)
    return `translateX(calc(100% - ${_offset}px))`
  }
  return ''
})

const fullscreenPhotoStore = useFullscreenPhotoStore()
const { type } = storeToRefs(fullscreenPhotoStore)
const { openSingle, openMultiple } = fullscreenPhotoStore
watch(
  () => props.fullscreen,
  async (v) => {
    if (v) {
      if (items.value.length <= FULLSCREEN_TYPE_THRESHOLD) {
        const { url } = items.value[currIndex.value]
        openSingle(await getDecryptDataBlob(url), props.watermark)
      } else {
        openMultiple(props.item, props.watermark)
      }
    }
  },
)
watch(type, (v) => {
  if (v === FULLSCREEN_PHOTO_TYPE.CLOSE) {
    emits('exit-fullscreen')
  }
})

// 統計觀看數據
if (props.statInfo) {
  let activeMs
  useStat(
    MEDIA_TYPE.PHOTO,
    () => props.active,
    () => props.statInfo,
    {
      activeFn: () => {
        activeMs = Date.now()
      },
      activeMs: () => {
        if (!activeMs) return 0
        const currMs = Date.now()
        return currMs - activeMs
      },
    },
  )
}

useOnceOrDbClick(
  photoSwiper,
  () => {},
  () => emits('dbclick'),
)
</script>

<style lang="scss" scoped>
.photo-swiper {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;

  &.swiping {
    .photo-item {
      transition: none;
      &.curr,
      &.prev,
      &.next {
        will-change: transform;
      }
    }
  }

  .photo-item {
    width: 100%;
    height: 100%;
    position: absolute;
    transition: transform 0.25s ease-out;

    &.prev,
    &.prev-out {
      transform: translateX(-100%);
    }

    &.next,
    &.next-out {
      transform: translateX(100%);
    }

    &.prev-out,
    &.next-out {
      display: none;
    }

    .view-more {
      width: inherit;
      height: inherit;
      position: absolute;
      top: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      backdrop-filter: blur(0.625rem);

      button {
        padding: 0.3125rem 1rem;
        background: rgb(24, 25, 37, 0.4);
        border: 1px solid #fff;
        border-radius: 3rem;
        color: #fff;
        // opacity: 0.4;
      }
    }
  }

  .index-number {
    width: fit-content;
    padding: 0 0.6875rem;
    border-radius: 0.628125rem;
    background: rgba(115, 115, 115, 0.5);
    color: #fff;
    position: absolute;
    top: 6.9375rem;
    right: 1.25rem;
  }

  .index-circle {
    width: fit-content;
    display: flex;
    position: absolute;
    bottom: 12rem;
    left: 50%;
    transform: translateX(-50%);

    .circle {
      width: 0.4375rem;
      height: 0.4375rem;
      border-radius: 0.4375rem;
      background: rgb(var(--v-theme-gray-x));
      opacity: 0.75;

      &.active {
        background: #fff;
        opacity: 1;
      }
    }
  }

  .arrow-left,
  .arrow-right {
    background: rgba(var(--v-theme-background), 0.6);
    border-radius: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    top: 50%;
    opacity: 0;
    transition: opacity 0.3s;
  }
  .arrow-left {
    left: 5rem;
    transform: rotate(180deg);
  }
  .arrow-right {
    right: 5rem;
  }
  &:hover {
    .arrow-left,
    .arrow-right {
      opacity: 1;
    }
  }
}
</style>
